#include "arplistener.h"
#include <QDebug>
#include "utils.h"
#include <QSet>
#include <QHostInfo>
#include <QCoreApplication>
#include <QtConcurrent>
#include "arp_types.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <nb30.h>

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "netapi32.lib")

const char* getHostnameFromIP(const char* ip) {

    static char hostname[NI_MAXHOST] = "";

    WSADATA wsaData;
    WSAStartup(MAKEWORD(2,2), &wsaData);

    struct sockaddr_in sa;
    memset(&sa, 0, sizeof(sa));
    sa.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &sa.sin_addr);

    if (getnameinfo((struct sockaddr*)&sa, sizeof(sa),
                    hostname, NI_MAXHOST,
                    NULL, 0, NI_NAMEREQD) != 0) {
        strcpy(hostname, "Unknown");
    }

    WSACleanup();

    return hostname;
}

void lookupHost(const QString &ipAddress)
{
    qDebug() << QHostInfo::fromName(ipAddress).hostName() << "," << ipAddress;
}

ArpListener::ArpListener(pcap_t *handle, const QString &dev_name, ArpPktCallback cb, QObject *parent)
    : QThread{parent},dev_name_{dev_name},cb_{cb}, handle_{handle}
{}

ArpListener::~ArpListener()
{
    stop_listen();
    quit();
    wait();
}


void ArpListener::run()
{
    auto f = QtConcurrent::run([this](){listen_arp_pkt();});
    qDebug() << "not ";
    exec();
}

bool ArpListener::event(QEvent * ev)
{
    if(ev->type() == IpAppending) {
        auto ip = dynamic_cast<MyEvent*>(ev)->ip;
        // qDebug() << dynamic_cast<MyEvent*>(ev)->ip;
        // QHostInfo::lookupHost(ip, [ip](const QHostInfo &host) {
        //                           // qDebug() << host.hostName() << "," << ip; ;
        //                       });
        return true;
    }

    return QThread::event(ev);;
}

void ArpListener::listen_arp_pkt()
{
    // 检查数据链路层是否为以太网
    if (pcap_datalink(handle_) != DLT_EN10MB) {
        qDebug() << "This program works only on Ethernet networks.";
        return;
    }

    // 设置ARP过滤器
    struct bpf_program fp;
    if (pcap_compile(handle_, &fp, "arp", 1, 0) == -1) {
        qDebug() << "Couldn't parse filter";
        pcap_close(handle_);
        return;
    }
    if (pcap_setfilter(handle_, &fp) == -1) {
        qDebug() << "Couldn't install filter";
        pcap_close(handle_);
        return;
    }
    qDebug() << QString("Listening on %1...").arg(dev_name_);

    qDebug() << "start capture";

    pcap_loop(handle_, 0, packet_handler, reinterpret_cast<uchar*>(this));
}

void ArpListener::stop_listen()
{
    if(handle_) pcap_breakloop(handle_);
}


void ArpListener::packet_handler(u_char *param, const pcap_pkthdr *header, const u_char *pkt_data)
{
    eth_header *peth_header;
    arp_packet *arp_hdr;
    ArpListener* p_this = reinterpret_cast<ArpListener*>(param);

    // 解析以太网头部
    peth_header = (eth_header*)pkt_data;

    // 检查是否是ARP包(以太网类型0x0806)
    if (ntohs(peth_header->ether_type) == 0x0806) {
        arp_hdr = (arp_packet *)(pkt_data + sizeof(eth_header));

        // qDebug() << "ARP Packet Captured:";

        // 打印操作类型
        switch (ntohs(arp_hdr->oper)) {
        // case 1: qDebug() << "Type: ARP Request"; break;
        // case 2: qDebug() << "Type: ARP Reply\n"; break;
        // default: qDebug() << "Type: Unknown ARP Operation " << ntohs(arp_hdr->oper); break;
        }
        if(ntohs(arp_hdr->oper) != 2) return;

        auto ip = ip2str(arp_hdr->spa);
        // qDebug() << "Sender MAC: " << mac2str(arp_hdr->sha) << ", IP: " << ip;
        // QHostInfo info;
        // lookupHost(ip);
        // QElapsedTimer timer;
        // timer.start();
        // qDebug() << getHostnameFromIP(ip.toStdString().data());
        // qDebug() << "Query took" << timer.elapsed() << "ms";
        // qDebug() << "Target MAC: " << mac2str(arp_hdr->tha) << ", IP: " << ip2str(arp_hdr->tpa);
        // static QSet<QString> ips;
        // static uint32_t total = 0;
        // if(!ips.contains(ip)) {
        //     ips.insert(ip);
        // }
        // ++total;
        // qDebug() << ips.count() << "/" << total;
        // QHostInfo::lookupHost(ip, [ip](const QHostInfo &host) {
        //                           qDebug() << host.hostName() << "," << ip; ;
        //                       });
        auto ev = new MyEvent(ip, IpAppending);
        QCoreApplication::postEvent(p_this, ev);
    }
}
